import * as PIXI from "pixi.js"; // https://www.npmjs.com/package/pixi.js
import { TweenMax,TimelineMax } from 'gsap/TweenMax' // tween动画库 https://www.npmjs.com/package/gsap
import AlloyTouch from 'alloytouch' //触控事件 https://www.npmjs.com/package/alloytouch
import PreCreatedText from '@/assets/js/PreCreatedText.js'   // 文字  精灵属性
import PreCreateResources from '@/assets/js/PreCreateResources.js'  // 图片素材  精灵属性
import spriteAnimation from '@/assets/js/spriteAnimation.js' // 图片精灵 动画属性
import textAnimation from '@/assets/js/textAnimation.js' // 文字精灵 动画属性
import chalks from '@/assets/chalk/index.js' // 控制台打印
import mitt from 'mitt' // 自定义监听事件 https://www.npmjs.com/package/mitt


/**
 * 装饰器 
 */
// function Decorator (){
//     return readline () {
//         return this.reader.readline
//     }
// }
/**
 * 创建场景
 */
// @Decorator
class createscene {
    constructor(config) {
        this.el = config.el // 场景容器
        this.width = config.el.offsetWidth // 场景宽
        this.height = config.el.offsetHeight // 场景高
        // 创建场景
        this.app = new PIXI.Application({
            resolution: 1,
            antialias: true,
            backgroundAlpha: true,
            width: this.width,
            height: this.height,
            backgroundColor: 0xcccccc
        })
        // 加入场景
        this.el.appendChild(this.app.view)
    }
}

/**
 * main
 */
class Steup extends createscene {  // 使用继承后 createscene 类 将被 Steup类完全继承，Steup可任意调用
    constructor(el) {
        super({ el }) //继承于场景 super 最先执行
        this.emitter = mitt()
        this.version = PIXI.VERSION // pixiJS 版本
        this.getResource = PreCreateResources.getResource() // 素材
        this.getSprites = PreCreateResources.getSprites() // 素材
        this.spritesAnimations = spriteAnimation // 精灵动画
        this.textsAnimations = PreCreatedText || {} // 文本集合
        this.textAnimation = textAnimation // 文本动画集合 
        this.scrollHeight = this.height * 3
        this.sprites = {}
        this.resources = {}
        this.texts = {}
        this.timeline = null // 时间轴
        this.alloyTouch = null// 
        this.touchOptions = {
            touch: this.el, // 反馈触摸的dom
            initialValue: 0, // 起始位置
            sensitivity: 1, // 不必需,触摸区域的灵敏度，默认值为1，可以为负数
            maxSpeed: 1, // 不必需，触摸反馈的最大速度限制
            min: -this.scrollHeight - this.height,
            max: 0,
            value: 0,
            change: this.touchmove.bind(this)
        },
            // 动画定时器
            this.aniIntervals = []
        this.load()
    }
    /**
     * load执行加载图片素材， 总进程
     */
    async load() {
        let i = 0
        const loader = new PIXI.Loader()
        loader.add(this.getResource)
        loader.onProgress.add(() => { })
        loader.onError.add((err) => { console.log(`${++i}` + err) })
        loader.onLoad.add(() => { })
        loader.onComplete.add(() => { })
        loader.load((loader, resources) => {
            PIXI.utils.clearTextureCache(); // 加载后清除缓存
            this.start(loader, resources)
        })
    }
    // 加载素材完毕 
    async start(loader, resources) {
        chalks.red(`PIXI图片纹理加载完毕！===>`)
        console.log(resources)
        chalks.Printing(`PIXI.JS ${this.version}`, '素材源自网络，仅供学习交流使用，请勿商用！')
        await this.CreateSpriteGroup(resources) // 创建精灵组
        await this.CreateInitTexts(resources) // 创建文字组
        await this.tweenAction() // tweenmax 时间轴 动画
        await this.initTouch() // touch 触控事件
    }
    /**
     * 
     * @param {*} resources 
     */
    // 创建 图片精灵组并加入到场景
    CreateSpriteGroup(resources) {
        Object.keys(this.getSprites).forEach((key) => {
            // 精灵对应 素材集合
            const options = this.getSprites[key]
            const sprite = new PIXI.Sprite(resources[options.key].texture)
            // 设置属性
            this.setSize(sprite, options.size)
            this.setAnchor(sprite, options.anchor)
            this.setPosition(sprite, options.position)
            // 加入场景
            this.app.stage.addChild(sprite)
            this.sprites[key] = sprite
            this.resources[key] = resources
        })
    }
    // 创建 文字精灵组并加入到场景
    CreateInitTexts() {
        Object.keys(this.textsAnimations).forEach((key) => {
            // 创建
            const options = this.textsAnimations[key]
            const text = new PIXI.Text(options.text, options.options)
            // 设置属性
            this.setAnchor(text, options.anchor)
            this.setPosition(text, options.position)
            // 设置点击事件
            if (options.link) {
                text.interactive = true
                text.on('tap', (e) => {
                    location.href = options.link
                })
            }
            // 加入场景
            this.app.stage.addChild(text)
            this.texts[key] = text
        })
    }
    /**
     * 配置精灵组属性
     * @param {*} obj 
     * @param {*} size 
     */
    // 设置尺寸
    setSize(obj, size) {
        if (size.mode === 'widthFit') { // 按宽度适应
            const scale = this.app.screen.width * size.width / obj.width
            obj.scale.x = scale
            obj.scale.y = scale
        } else if (size.mode === 'heightFit') { // 按高度适应
            const scale = this.app.screen.height * size.height / obj.height
            obj.scale.x = scale
            obj.scale.y = scale
        } else { // 自定义
            obj.width = size.width
            obj.height = size.height
        }
    }
    // 设置锚点
    setAnchor(obj, anchor) {
        if (typeof anchor === 'string') {
            const anchorMap = this.positionMap(anchor)
            obj.anchor.x = anchorMap.x
            obj.anchor.y = anchorMap.y
        } else {
            obj.anchor.x = anchor.x
            obj.anchor.y = anchor.y
        }
    }
    // 设置位置
    setPosition(obj, position) {
        if (typeof position === 'string') {
            position = this.positionMap(position)
        }
        obj.position.x = position.x * this.app.screen.width
        obj.position.y = position.y * this.app.screen.height
    }
    // 位置转换
    positionMap(type) {
        const map = {
            top: { x: 0.5, y: 0 },
            right: { x: 1, y: 0.5 },
            bottom: { x: 0.5, y: 1 },
            left: { x: 0, y: 0.5 },
            topLeft: { x: 0, y: 0 },
            topRight: { x: 1, y: 0 },
            bottomLeft: { x: 0, y: 1 },
            bottomRight: { x: 1, y: 1 },
            center: { x: 0.5, y: 0.5 }
        }
        return map[type] || { x: 0, y: 0 }
    }
    /**
     * 配置精灵属性
     * @param {*}  
     */
    tweenAction() {
        this.timeline = new TimelineMax({
            paused: true
        })
        // 设置精灵动画
        Object.keys(this.spritesAnimations).forEach((key) => {
            this.setAnimation(this.sprites[key], this.spritesAnimations[key], this.resources[key], key)
        })

        // 设置文本动画
        Object.keys(this.textsAnimations).forEach((key) => {
            this.setAnimation(this.texts[key], this.textAnimation[key])
        })
    }

    // 动画对象
    setAnimation(obj, animations, resources, key) {
        if (obj && animations && animations instanceof Array) {
            animations.forEach(({ from, to, frames, infinite, frameRate, delay = 0, duration = 1 }) => {
                if (frames) { // 帧动画 
                    console.log(infinite)
                    infinite && this.onInfinite(obj, frameRate, frames, key)
                    infinite || this.emitter.on('progress', progress => { //  挂载时间轴 监听事件
                        const frameProgress = (progress - delay) / duration
                        let index = Math.floor(frameProgress * frames.length)
                        if (index < frames.length && index >= 0) {
                            const frame = frames[index]
                            obj.texture = resources[frame].texture
                        }
                    })
                }
                if (from || to) {// 过渡动画
                    let action
                    if (from && to) {
                        action = TweenMax.fromTo(obj, duration, from, to)
                    } else if (to) {
                        action = TweenMax.to(obj, duration, to)
                    } else if (from) {
                        action = TweenMax.from(obj, duration, from)
                    }
                    const timeline = new TimelineMax({ delay })
                    timeline.add(action, 0)
                    timeline.play()
                    if (!(to && to.repeat === -1)) {
                        this.timeline.add(timeline, 0)
                    }
                }
            })
        }
    }
    /**  
    * 无限循环动画
    * @param {*} obj 要改变的对象
    * @param {*} frameRate 动画循环速度 --数越大 动画越快
    * @param {*} frames 精灵的名称 集合
    */
    onInfinite(obj, frameRate, frames,key) {
        obj.frames = frames
        obj.currentFrame = 0
        this.aniIntervals.push(setInterval(() => {
          obj.currentFrame += 1
          if (obj.currentFrame >= obj.frames.length) obj.currentFrame = 0
          const frame = obj.frames[obj.currentFrame]
          obj.texture = this.resources[key][frame].texture
        }, 1000 / frameRate))
    }
    /**
     * touch 触控
     */
    initTouch() {
        try {
            this.alloyTouch = new AlloyTouch(this.touchOptions)
        } catch (err) {
            console.log(err)
        }
    }
    touchmove(value) {
        // 总播放进度
        // console.log(value)
        this.progress = -value / this.scrollHeight
        this.progress = this.progress < 0 ? 0 : this.progress
        this.progress = this.progress > 1 ? 1 : this.progress
        // 控制进度条
        this.timeline.seek(this.progress)
        // 触发 监听事件 
        this.emitter.emit('progress', this.progress)
    }
}
export default Steup
